package buscawiki;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Universidad Simón Bolívar
 * Sede Sartenejas
 * Departamento de Computación y Tecnologías de la Información
 * Traductores e Interpretadores (CI-3725)
 * Trimestre Sep-Dic 2009
 *
 * Proyecto 1: Busqueda por Relevancia
 *
 * @author Jofran Peña Durán
 * @author Richard Simoes Ferreira 03-36514
 */
public class Relevancia {
    
    private Pattern expReg;
    private Pattern expRegP;
    private Pattern expReg5;
    private Pattern expReg2;
    private Pattern expReg22;
    private Pattern expRegTitle;
    private Pattern expRegR;
    
    private static File archivo;
    private static BufferedReader lector;
    public LinkedList<Registro> lista;

/**
 * Crea una nueva instancia de una busqueda por relevancia.
 * <p>
 * Recibe una expresión regular aceptada por la librería Regex de Java junto
 * con la dirección absoluta del fragmento de wikipedia sobre el cuál
 *  se va a ejecutar la busqueda.
 * @param expReg una expresión regular aceptada por la librería Regex de Java
 * @param path dirección absoluta del fragmento de wikipedia donde se
 * va a realizar la búsqueda
 * @throws IOException si hay algun problema relacionado con el documento.
 */
    public Relevancia(String expReg, String path) throws Exception{
        //ExpReg de entrada
        String expRegular = expReg;
        //ExpReg de palabra
        String expRegularP = "\\b"+expReg+"\\b";
        //ExpReg de seccion
        String expRegular5 = "==+.*==+";
        //ExpReg de enlace interno
        String expRegular2 = "\\[\\[(\\s|\\w)*\\|?(\\s|\\w)*\\]\\]";
        //ExpReg de enlace externo
        String expRegular22 = "\\[http.*\\]";
        //ExpReg de enlace prohibido tipo [ : ]
        String expRegularR = "\\[\\[(\\s|\\w)*:.*\\]\\]";
        
        this.expReg = Pattern.compile(expRegular);
        expRegP = Pattern.compile(expRegularP);
        expReg5 = Pattern.compile(expRegular5);
        expReg2 = Pattern.compile(expRegular2);
        expReg22 = Pattern.compile(expRegular22);
        expRegTitle = Pattern.compile("\\s*<title>.*</title>");
        expRegR = Pattern.compile(expRegularR);
        
        lista = new LinkedList();
        archivo = new File(path);
        lector = new BufferedReader(new FileReader(archivo));
        
    }

    /**
     * Calcula la relevancia de cada artículo de wikipedia, dadas las
     * siguientes convenciones:
     * <p>
     * 50 puntos de relevancia si la única palabra del título del artículo es
     * aceptada por la expresión regular.
     * <p>
     * 10 puntos por cada palabra del título que sea aceptada por la expresión
     * regular si el título tiene más de una palabra.
     * <p>
     * 5 puntos por cada palabra de un título de sección que sea
     * aceptada por la expresión regular.
     * <p>
     * 2 puntos por cada palabra en un enlaceque sea aceptada por la
     * expresión regular.
     * <p>
     * 1 punto por cada palabra del cuerpo del artículo aceptada por
     * la expresión regular.
     * <p>
     * Considerando que:
     * <p>
     * Una palabra es una secuencia de caracteres alfanuméricos donde las letras
     * pueden o no tener signos de acentuación tal como está definido para las
     * librerías de expresiones regulares de los lenguajes a utilizar.
     * <p>
     * Una expresión regular aceota una palabra si la palabra desde principio
     * a fin es aceptada por la expresión.
     */
    public void leerRelev() {
        try {
            String linea;
            Registro aux;
            
            while(lector.ready()){
                linea = lector.readLine();
                Matcher titulo = expRegTitle.matcher(linea);
                int numenlaces = 0;
                int numenlacesext = 0;
                int numenlacesimg = 0;
        	/*Si es un título le suma la relevancia correspondiente*/
	            if (titulo.matches()) {
                        buscarTitulo(linea);
	            } else {
                        /*Se crean 5 matchers para determinar los distintos
                        tipos de relevancia sobre la misma linea*/
                        Matcher seccion = expReg5.matcher(linea);
                        Matcher enlace = expReg2.matcher(linea);
                        Matcher enlacext = expReg22.matcher(linea);
                        Matcher texto = expRegP.matcher(linea);
                        Matcher enlaceimg = expRegR.matcher(linea);
                        Matcher maux;
                        /*Buscamos los enlaces internos*/
                        while (enlace.find()){
                            aux = (Registro) lista.getFirst();
                            maux = expRegP.matcher(enlace.group());
                            while (maux.find()) {
                                aux.relevancia += 2;
                                numenlaces += 1;
                            }
                        }
                        /*Buscamos los enlaces externos*/
                        while (enlacext.find()){
                            aux = (Registro) lista.getFirst();
                            maux = expRegP.matcher(enlacext.group());
                            while (maux.find()) {
                                aux.relevancia += 2;
                                numenlacesext += 1;
                            }
                        }
                        /*Buscamos los enlaces de imagenes, o los enlaces
                        que tengan dos puntos adentro*/
                        while (enlaceimg.find()){
                            maux = expRegP.matcher(enlaceimg.group());
                            while (maux.find()) {
                                numenlacesimg += 1;
                            }
                        }
                        /*Buscamos las secciones*/
                        if (seccion.matches()){
                            aux = (Registro)lista.getFirst();
                            seccion = expRegP.matcher(linea);
                            while (seccion.find()) {
                                aux.relevancia += 5;
                            }
                        } else {
                            /*Sino no queda de otra opción que tener puntos de
                             relevancia por contenido, luego buscamos
                             palabras aceptadas de tipo contenido*/
                            if(texto.find()){
                              aux = (Registro) lista.getFirst();
                              /*Para no contar dos veces palabras de enlace como
                                texto restamos todas las veces que encontramos
                                palabras en las busquedas anteriores*/
                              int suma = numenlaces+numenlacesext+numenlacesimg;
                              aux.relevancia -= suma;
                              aux.relevancia += 1;
                              while(texto.find()){
                                  aux.relevancia += 1;
                              }
                            }
                        }
                    }
                }
            imprimirRelev(lista);
        }catch (IOException e) {
            e.printStackTrace();
        }finally{
            try{
                lector.close();
            }catch(IOException e1){
                e1.getMessage();
            }
        }
    }
    /**
     * Reemplaza el String linea quitandole los caracteres que se especifiquen
     * en la ExpReg etiqueta.
     * @param linea String que deseamos filtrar
     * @param etiqueta ExpReg que representa los caracteres que desamos
     * reemplazar del String
     * @return la linea sin los caracteres especificados en etiqueta
     */
    public String reemplazar (String linea, String etiqueta){
            /*Se quitan las etiquetas*/
            String remover = etiqueta;
            String reemplazo = "";
            Pattern p = Pattern.compile(remover);
            Matcher m = p.matcher(linea);
            linea = m.replaceAll(reemplazo);
	    return linea;
    }
    /**
     * Destermina si el articulo suma 50 puntos de relevancia si su unica
     * palabra es aceptada por la expresión regular dada, o si suma 10 cada vez
     *  que alguna palabra del título es aceptada por la RegEx, o suma
     * relevancia 0 si no tiene ninguna palabra que sea aceptada por la RegEx
     * @param linea contine un título de un artículo Wikipedia
     */
    public void buscarTitulo(String linea) {
        linea = reemplazar (linea,"\\s*</?title>");
        Registro reg = new Registro(linea);
        Matcher unicaPalabra = expReg.matcher(linea);
        Matcher palabra = expRegP.matcher(linea);
        if (unicaPalabra.matches()){
            reg.relevancia += 50;
        } else {
            while (palabra.find()) {
                reg.relevancia += 10;
            }
        }
        lista.addFirst(reg);
    }     
    /**
     * Imprime una lista ordenada por relevancia con los títulos de los
     * artículos que tengan una palabra que sea aceptada por la ExpReg dada y
     * cuya relevancia sea distinta de cero.
     * @param lista Lista de títulos de los artículos leídos de wikipedia
     */
    public void imprimirRelev(LinkedList<Registro> lista){
        /*No queremos imprimir títulos con relevancia 0*/
        elimRelevCero(lista);
        Collections.sort(lista);
        Collections.reverse(lista);
        Iterator iterator;
        Registro registro;
        iterator = lista.iterator();
        while (iterator.hasNext()){
            registro = (Registro) iterator.next();
            System.out.print(registro.relevancia+"   "+registro.titulo+"\n");
        }                 
    }
    /**
     * Elimina los elementos de la lista de títulos que tengan relevancia cero
     * @param lista Lista de títulos de los artículos leídos de wikipedia
     */
    public void elimRelevCero(LinkedList<Registro> lista){
        Iterator iterator;
        iterator = lista.iterator();  
        Registro registro;
        while (iterator.hasNext()){
            registro = (Registro) iterator.next();
            if(registro.relevancia == 0){
                iterator.remove();
            }  
        }
    }
}


